/*  Nanhill Data Bind JavaScript Library
 *  
 *  version 1.0.1 2006-03-31
 * 		add table bind.
 *
 *  (c) 2005 alin <xalinx@gmail.com>
 *	need Nhill util.js, prototype.js
 * 
 *  Nanhill javascript library is freely distributable under the terms 
 * 	of an Apache license. For details, see the Nanhill web site: 
 *  http://sourceforge.net/projects/nanhillplatform
/*--------------------------------------------------------------------------*/
/*
Object.extend(Sro.prototype, {
	bindReply : function(service, params, bindElemId) {
		this.remoteCall(service, params, function(reply) {
			NHBind.bind(bindElemId, reply.getResult());
		})
	}
});
*/
var NHBind = {
	bind : function(elementId, bindValue) {
		var elem =  $(elementId);
		switch(elem.tagName.toLowerCase()) {
			case "input": 
				switch (elem.type.toLowerCase()) {
					case "text": ;
					case "hidden": ;
					case "password": SroBind.Factory.bindText(elem, bindValue); break;
					case "checkbox": ;
					case "radio": SroBind.Factory.bindRadioOrCheckbox(elem, bindValue); break;
				}
				break;
			case "textarea":
				SroBind.Factory.bindText(elem, bindValue);
				break; 
			case "table": 
				SroBind.Factory.bindTable(elem, bindValue);
				break; 
			case "select": 
				SroBind.Factory.bindSelect(elem, bindValue);
				break; 
			case "div":
			case "span":
				alert(bindValue);
				elem.innerHTML = bindValue;
				break;
			//TODO: add more bindings here 
		}
	}
}

NHBind.Factory = {
	reportError: function(elem, value, msg) { 
		throw "Data bind failed: " + msg;
	},
	
	bindText: function(elem, value) { 
		elem.value = value;
	},
	
	bindRadioOrCheckbox: function(elem, value) {
		var ret = false;
		switch (typeof(value)) {
			case 'boolean': ret = value; break;
			case 'string': ret = (value == "1" || value == "true" || value == "yes"); break;
			case 'number': ret = (parseInt(value) == 1); break;
			default: ret = false;
		}
		elem.checked = ret;
	},

	bindSelect : function(elem, value) {
		//TODO: Check the data type
		if (typeof(value) != "object" || value.constructor != Array) {
			this.reportError(elem,value,"Array Type Needed for binding select!");
		}
		// delete all the nodes.
		while (elem.childNodes.length > 0) {
			elem.removeChild(elem.childNodes[0]);
		}
		
		// bind data
		for (var i = 0; i < value.length; i++) {
			var option = document.createElement("OPTION");
			var data = value[i];
			if (data == null || typeof(data) == "undefined") {
				option.value = "";
				option.text = "";
			}
			if (typeof(data) != 'object') {
				option.value = data;
				option.text = data;
			} else {
				option.value = data[elem.getAttribute("jvalue")];
				option.text = data[elem.getAttribute("jtext")];	
			}
			elem.options.add(option);
		}
	},

	bindTable: function(elem, value) {
		var jHeight = parseInt(elem.getAttribute("jheight"));
		var dataHeader = [];
		var tBody = elem.getElementsByTagName("TBODY")[0];
		// clear the generated rows
		if (elem.getElementsByTagName("TBODY").length > 0) {
			while (tBody.rows.length > jHeight) {
					tBody.deleteRow(jHeight);
			}
		}
		if (jHeight == 0) { // if table is null, push the data to the tables.
			for (x in value[0] ) {
				dataHeader[dataHeader.length] = x;
			}
			var hTr = elem.insertRow(elem.rows.length);
			for (var i = 0; i < dataHeader.length; i++) {
				var td = hTr.insertCell(hTr.cells.length);
				td.innerHTML = dataHeader[i];
			}
			for (var i = 0; i < value.length; i++) {
				var tr = elem.insertRow(elem.rows.length);
				var data = value[i];
				for (x in data ) {
					var td = tr.insertCell(tr.cells.length);
					td.innerHTML = data[x];
				}
			}	
		}
		if (jHeight == 1) { // if there is only one line, first line is header(every td indicate by a jtext property)
			var headerTR = tBody.rows[0];
			for (var i = 0; i < headerTR.cells.length ; i++ ) {
				dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
			}
			for (var i = 0; i < value.length; i++) {
				var tr = tBody.insertRow(tBody.rows.length);
				var data = value[i];
				for (var j = 0; j < dataHeader.length; j++ ) {
					var td = tr.insertCell(tr.cells.length);
					td.innerHTML = data[dataHeader[j]];
				}
			}	
		}

		if (jHeight == 2) { // two lines, first line is header, the second is style
			var headerTR = tBody.rows[0];
			for (var i = 0; i < headerTR.cells.length ; i++ ) {
				dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
			}
			for (var i = 0; i < value.length; i++) {
				var tr;
				if (i == 0) { // if the first row
					tr = elem.rows[1];
				} else { // else copy the first row
					tr = elem.rows[1].cloneNode(true);
				}
				if (i > 0) 	{
					tBody.appendChild(tr);
				}
				var data = value[i];
				for (var j = 0; j < tr.cells.length; j++ ) {
					var td = tr.cells[j];
					
					td.innerHTML = data[dataHeader[j]];
				}
			}	
		}

		if (jHeight >= 3) { // more than 3 rows, first header, second and third is odd/even style, other lines ommited.
			var headerTR = tBody.rows[0];
			for (var i = 0; i < headerTR.cells.length ; i++ ) {
				dataHeader[dataHeader.length] = headerTR.cells[i].getAttribute("jtext");
			}
			for (var i = 0; i < value.length; i++) {
				var tr;
				if (i == 0) { // 1st row
					tr = tBody.rows[1];
				} else if (i == 1) 	{ // 2nd row
					tr = tBody.rows[2];
				} else if ( i % 2 == 0) { // get the 1st row
					tr = tBody.rows[1].cloneNode(true);
				} else if (i % 2 == 1) { // the 2nd row
					tr = tBody.rows[2].cloneNode(true);
				}
				if (i > 1) 	{
					tBody.appendChild(tr);
				}
				var data = value[i];
				for (var j = 0; j < tr.cells.length; j++ ) {
					var td = tr.cells[j];	
					td.innerHTML = data[dataHeader[j]];
				}
			}	
		}
	},
	
	bindRepeater:function(elem, value) {
		//TODO: implementation will be added.
	}

}
// {{ table creator
/**
 * Create rows inside a the table, tbody, thead or tfoot element (given by id).
 * @see http://getahead.ltd.uk/dwr/browser/tables
 */
NHBind.addRows = function(ele, data, cellFuncs, options) {
  var orig = ele;
  ele = $(ele);
  if (ele == null) {
    NHUtil.debug("addRows() can't find an element with id: " + orig + ".");
    return;
  }
  if (!NHBind._isHTMLElement(ele, ["table", "tbody", "thead", "tfoot"])) {
    NHUtil.debug("addRows() can only be used with table, tbody, thead and tfoot elements. Attempt to use: " + NHUtil.typeOf(ele));
    return;
  }
  if (!options) options = {};
  if (!options.rowCreator) options.rowCreator = NHBind._defaultRowCreator;
  if (!options.cellCreator) options.cellCreator = NHBind._defaultCellCreator;
  var tr, rowNum;
  if (NHUtil.isArray(data)) {
    for (rowNum = 0; rowNum < data.length; rowNum++) {
      options.rowData = data[rowNum];
      options.rowIndex = rowNum;
      options.rowNum = rowNum;
      options.data = null;
      options.cellNum = -1;
      tr = NHBind._addRowInner(cellFuncs, options);
      if (tr != null) ele.appendChild(tr);
    }
  }
  else if (typeof data == "object") {
    rowNum = 0;
    for (var rowIndex in data) {
      options.rowData = data[rowIndex];
      options.rowIndex = rowIndex;
      options.rowNum = rowNum;
      options.data = null;
      options.cellNum = -1;
      tr = NHBind._addRowInner(cellFuncs, options);
      if (tr != null) ele.appendChild(tr);
      rowNum++;
    }
  }
};

/**
 * @private Internal function to draw a single row of a table.
 */
NHBind._addRowInner = function(cellFuncs, options) {
  var tr = options.rowCreator(options);
  if (tr == null) return null;
  for (var cellNum = 0; cellNum < cellFuncs.length; cellNum++) {
    var func = cellFuncs[cellNum];
    var td;
    //if (typeof func == "string") {
    //  options.data = func;
    //  options.cellNum = cellNum;
    //  td = options.cellCreator(options);
    //  td.appendChild(document.createTextNode(func));
    //}
    //else {
      var reply = func(options.rowData);
      options.data = reply;
      options.cellNum = cellNum;
      td = options.cellCreator(options);
      if (NHBind._isHTMLElement(reply, "td")) td = reply;
      else if (NHBind._isHTMLElement(reply)) td.appendChild(reply);
      else td.innerHTML = reply;
    //}
    tr.appendChild(td);
  }
  return tr;
};

/**
 * @private Default row creation function
 */
NHBind._defaultRowCreator = function(options) {
  return document.createElement("tr");
};

/**
 * @private Default cell creation function
 */
NHBind._defaultCellCreator = function(options) {
  return document.createElement("td");
};

/**
 * Remove all the children of a given node.
 * @see http://getahead.ltd.uk/dwr/browser/tables
 */
NHBind.removeAllRows = function(ele) {
  var orig = ele;
  ele = $(ele);
  if (ele == null) {
    NHUtil.debug("removeAllRows() can't find an element with id: " + orig + ".");
    return;
  }
  if (!NHBind._isHTMLElement(ele, ["table", "tbody", "thead", "tfoot"])) {
    NHUtil.debug("removeAllRows() can only be used with table, tbody, thead and tfoot elements. Attempt to use: " + NHUtil.typeOf(ele));
    return;
  }
  while (ele.childNodes.length > 0) {
    ele.removeChild(ele.firstChild);
  }
};

/**
 * @private Is the given node an HTML element (optionally of a given type)?
 * @param ele The element to test
 * @param nodeName eg "input", "textarea" - check for node name (optional)
 *         if nodeName is an array then check all for a match.
 */
NHBind._isHTMLElement = function(ele, nodeName) {
  if (ele == null || typeof ele != "object" || ele.nodeName == null) {
    return false;
  }

  if (nodeName != null) {
    var test = ele.nodeName.toLowerCase();

    if (typeof nodeName == "string") {
      return test == nodeName.toLowerCase();
    }

    if (NHUtil.isArray(nodeName)) {
      var match = false;
      for (var i = 0; i < nodeName.length && !match; i++) {
        if (test == nodeName[i].toLowerCase()) {
          match =  true;
        }
      }
      return match;
    }

    NHUtil.debug("NHBind._isHTMLElement was passed test node name that is neither a string or array of strings");
    return false;
  }

  return true;
};
//}}

//{{ pagination 
NHBind.Page = Class.create();
NHBind.Page.prototype = {
	initialize: function(pageId, pageSize, sum) {
		this.pageId = pageId;
		this.pageSize = pageSize;
		this.sum = sum;
		this.methodName = "";
	},
	
	getPageTotal : function() {
		var pageTotal = parseInt(this.sum / this.pageSize);
		return 0 == this.sum % this.pageSize ? pageTotal : pageTotal + 1;
	},
	
	getRowId : function() {
		return (this.pageId - 1) * this.pageSize + 1;
	},
	
	getStartIndex : function() {
		return this.getRowId() - 1;
	},
	
	getEndIndex : function() {
		return this.getStartIndex() + this.pageSize ;
	},
	

	
	addPage : function(index) {
		return index == this.pageId ? index + "&nbsp;" : "<a href='#' onclick='" + this.methodName + "(" + index +  ")'>" + index + "</a>,&nbsp;";
	},
	
	getPre : function() {
		return this.pageId == 1 ? "" : "<a href='#' onclick='" + this.methodName + "(" + (this.pageId - 1) + ")'>" + "???</a>&nbsp;";
	},
	
	getNext : function() {
		var pageTotal = this.getPageTotal();
		return this.pageId == pageTotal || 1 == pageTotal? "" : "<a href='#' onclick='"+ this.methodName +"(" + (this.pageId + 1) + ")'>" + "???</a>&nbsp;";
	},
	
	createIndex : function () {
		var maxBlock = 6;
		var block = 3;
		var all = maxBlock + block;
		var indexs = "";
		var pageTotal = this.getPageTotal();
		if (0 == this.sum || 1 == pageTotal) {
			return indexs;
		}

		indexs += "<div style='float:left;text-align:left;'>?" + pageTotal + "?" + this.sum + "?," + "??" + this.pageSize + "?,???"+ this.pageId +"?</div>"; 
		indexs += "<div>";
		indexs += this.getPre();
		// total: 1 ~ 9
		if(pageTotal <= all) {
			for (var i = 1; i <= pageTotal; i ++) {
				indexs += this.addPage(i);
			}
		// total: 10 ~
		} else {
			// pageId: 1 ~ 5
			if(this.pageId <= maxBlock - 1 ) {
				for (var i = 1; i <= this.pageId + 1 || i <= block; i ++) {
					indexs += this.addPage(i);
				}
				indexs += "&nbsp;...&nbsp;";
				for (var i = pageTotal - 2; i <= pageTotal; i ++) {
					indexs += this.addPage(i);
				}				
			// pageId: 6 ~
			} else {
				for (var i = 1; i <= block; i ++) {
					indexs += this.addPage(i);
				}
				indexs += "&nbsp;...&nbsp;";
				
				var leftEdge = pageTotal - maxBlock + 1;
				//alert(leftEdge);
				if (this.pageId > leftEdge) {
					for (var i = leftEdge; i <= pageTotal; i ++) {
						indexs += this.addPage(i);
					}					
				} else {
					for (var i = this.pageId - 1; i <= this.pageId + 1; i ++) {
						indexs += this.addPage(i);
					}
					indexs += "&nbsp;...&nbsp;";
					for (var i = pageTotal - 2; i <= pageTotal; i ++) {
						indexs += this.addPage(i);
					}
				}
			} 
		}	
		indexs += this.getNext();
		indexs += "</div>";
		return indexs;
	}
}
//}}
